package pl.gettoknowme.mobile.android;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import pl.gettoknowme.mobile.android.integration.PeriodicalIntegrationReceiver;
import pl.gettoknowme.mobile.android.model.DBAdapter;
import pl.gettoknowme.mobile.android.model.DBOpenHelper;
import pl.gettoknowme.mobile.android.model.dbtypes.Integration;
import pl.gettoknowme.mobile.android.model.dbtypes.UserSettings;
import pl.gettoknowme.mobile.android.model.dbtypes.Integration.IntegrationType;
import pl.gettoknowme.mobile.android.services.location.LocationAlarmReceiver;
import pl.gettoknowme.mobile.android.util.Constants;
import pl.gettoknowme.mobile.android.util.LoggingUtil;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

/**
 * Główny ekran aplikacji
 * @author Michał Kołodziejski
 */
public class MainActivity extends Activity {

    private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    private static final String FIRST_RUN_SHARED_PREFERENCES_KEY = "after_first_run";
    
    private Handler handler = new Handler();
    private DBAdapter dbAdapter;
    private LinearLayout topLayout;
    
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        doInitialSettings();
        
        Context ctx = getApplicationContext();
        dbAdapter = DBAdapter.getInstance(ctx);

        setContentView(R.layout.main);
        topLayout = (LinearLayout) findViewById(R.id.main_linear_layout);
        
        // rozpoczęcie jednorazowej integracji
        Button startIntegrationButton = (Button) findViewById(R.id.start_integration_button);
        startIntegrationButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // rozpoczęcie integracji
                startIntegration();
            }
        });
        
        // rozpoczęcie okresowej integracji
        Button startPeriodicalIntegrationButton = (Button) findViewById(R.id.start_periodical_integration_button);
        startPeriodicalIntegrationButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // rozpoczęcie okresowej integracji
                startPeriodicalIntegration();
                refreshView();
            }
        });
        
        // zatrzymanie okresowej integracji
        Button stopPeriodicalIntegrationButton = (Button) findViewById(R.id.stop_periodical_integration_button);
        stopPeriodicalIntegrationButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // zatrzymanie okresowej integracji
                stopPeriodicalIntegration();
                refreshView();
            }
        });
        
        
        // rozpoczęcie pobierania lokalizacji
        Button startFetchingLocationButton = (Button) findViewById(R.id.start_fetching_location_button);
        startFetchingLocationButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startLocationService();
                refreshView();
            }
        });
        
        
        // zatrzymanie pobierania lokalizacji
        Button stopFetchingLocationButton = (Button) findViewById(R.id.stop_fetching_location_button);
        stopFetchingLocationButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopLocationService();
                refreshView();
            }
        });
        
        // pokazywanie / ukrywanie sekcji przycisków kontrolnych
        Button showHideButtonsSection = (Button) findViewById(R.id.show_hide_buttons_section_button);
        showHideButtonsSection.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                View sectionView = findViewById(R.id.buttons_section);
                if(sectionView.getVisibility() == View.GONE){
                    sectionView.setVisibility(View.VISIBLE);
                } else {
                    sectionView.setVisibility(View.GONE);
                }
            }
        });
    }
    
    
    @Override
    protected void onResume() {
        super.onResume();
        
        // wypełenienie danych na ekranie
        refreshView();
    }
    
    
    /**
     * Wypełnia dane na widoku
     */
    private void refreshView(){
        handler.post(new Runnable() {
            @Override
            public void run() {
                fillUserData();
                fillLocationIntegrationData();
                fillSmsStatsIntegrationData();
                fillCallsStatsIntegrationData();
                fillLocationServiceStatus();
                fillPeriodicalIntegrationStatus();
            }
        });
    }
    
    
    private void fillUserData(){
        UserSettings userSettings = dbAdapter.getUserSettingsDAO().getUserSettings();
        TextView userId = (TextView) topLayout.findViewById(R.id.user_id);
        userId.setText(userSettings.getUserId());
    }

    /**
     * Pobiera dane o integracji lokalizacji z bazy danych i wypełnia
     * nimi widok
     */
    private void fillLocationIntegrationData(){
        long lastSuccessful = -1l;
        long lastFailed = -1l;
        int numberOfSuccessful = 0;
        int numberOfFailed = 0;
        
        int numberOfFetched = dbAdapter.getLocationDAO().getLocationList().size();
        
        List<Integration> integrationsList = dbAdapter.getIntegrationDAO()
                .getIntegrationList(IntegrationType.LOCATION);
        for (Integration integration : integrationsList) {
            if(integration.isSuccessful()){
                lastSuccessful = integration.getIntegrationTime();
                ++numberOfSuccessful;
            } else {
                lastFailed = integration.getIntegrationTime();
                ++numberOfFailed;
            }
        }
        
        fillLocationIntegrationData(lastSuccessful, lastFailed, numberOfSuccessful,
                numberOfFailed, numberOfFetched);
    }
    
    /**
     * Wypełnia danymi widoki sekcji o integracji lokalizacji
     * 
     * @param lastSuccessful ostatnia udana integracja
     * @param lastFailed ostatnia nieudana integracja
     * @param numberOfSuccessful liczba udanych integracji
     * @param numberOfFailed liczba nieudanych integracji
     * @param numberOfFetched liczba lokalizacji pobranych od ostatniej integracji
     */
    private void fillLocationIntegrationData(long lastSuccessful, long lastFailed,
            int numberOfSuccessful, int numberOfFailed, int numberOfFetched){
        TextView lastSuccessfulView = (TextView) topLayout
                .findViewById(R.id.location_last_successful);
        TextView lastFailedView = (TextView) topLayout
                .findViewById(R.id.location_last_failed);
        TextView numberOfSuccessfulView = (TextView) topLayout
                .findViewById(R.id.location_number_of_successful);
        TextView numberOfFailedView = (TextView) topLayout
                .findViewById(R.id.location_number_of_failed);
        TextView numberOfFetchedView = (TextView) topLayout
                .findViewById(R.id.location_number_of_fetched_since_last_integration);
        
        if(lastSuccessful != -1l){
            lastSuccessfulView.setText(DATE_FORMATTER.format(new Date(lastSuccessful)));
        }
        if(lastFailed != -1l){
            lastFailedView.setText(DATE_FORMATTER.format(new Date(lastFailed)));
        }
        numberOfSuccessfulView.setText(String.valueOf(numberOfSuccessful));
        numberOfFailedView.setText(String.valueOf(numberOfFailed));
        numberOfFetchedView.setText(String.valueOf(numberOfFetched));
    }
    

    /**
     * Pobiera dane o integracji statystyk SMS-ów z bazy danych i wypełnia
     * nimi widok
     */
    private void fillSmsStatsIntegrationData(){
        long lastSuccessful = -1l;
        long lastFailed = -1l;
        int numberOfSuccessful = 0;
        int numberOfFailed = 0;
        
        List<Integration> integrationsList = dbAdapter.getIntegrationDAO()
                .getIntegrationList(IntegrationType.SMS_STATS);
        for (Integration integration : integrationsList) {
            if(integration.isSuccessful()){
                lastSuccessful = integration.getIntegrationTime();
                ++numberOfSuccessful;
            } else {
                lastFailed = integration.getIntegrationTime();
                ++numberOfFailed;
            }
        }
        
        fillSmsStatsIntegrationData(lastSuccessful, lastFailed, numberOfSuccessful, numberOfFailed);
    }
    
    /**
     * Wypełnia danymi widoki sekcji o integracji statystyk SMS-ów
     * 
     * @param lastSuccessful ostatnia udana integracja
     * @param lastFailed ostatnia nieudana integracja
     * @param numberOfSuccessful liczba udanych integracji
     * @param numberOfFailed liczba nieudanych integracji
     */
    private void fillSmsStatsIntegrationData(long lastSuccessful, long lastFailed,
            int numberOfSuccessful, int numberOfFailed){
        TextView lastSuccessfulView = (TextView) topLayout
                .findViewById(R.id.sms_last_successful);
        TextView lastFailedView = (TextView) topLayout
                .findViewById(R.id.sms_last_failed);
        TextView numberOfSuccessfulView = (TextView) topLayout
                .findViewById(R.id.sms_number_of_successful);
        TextView numberOfFailedView = (TextView) topLayout
                .findViewById(R.id.sms_number_of_failed);
        
        if(lastSuccessful != -1l){
            lastSuccessfulView.setText(DATE_FORMATTER.format(new Date(lastSuccessful)));
        }
        if(lastFailed != -1l){
            lastFailedView.setText(DATE_FORMATTER.format(new Date(lastFailed)));
        }
        numberOfSuccessfulView.setText(String.valueOf(numberOfSuccessful));
        numberOfFailedView.setText(String.valueOf(numberOfFailed));
    }

    /**
     * Pobiera dane o integracji statystyk połączeń telefonicznych z bazy danych i wypełnia
     * nimi widok
     */
    private void fillCallsStatsIntegrationData(){
        long lastSuccessful = -1l;
        long lastFailed = -1l;
        int numberOfSuccessful = 0;
        int numberOfFailed = 0;
        
        List<Integration> integrationsList = dbAdapter.getIntegrationDAO()
                .getIntegrationList(IntegrationType.CALLS_STATS);
        for (Integration integration : integrationsList) {
            if(integration.isSuccessful()){
                lastSuccessful = integration.getIntegrationTime();
                ++numberOfSuccessful;
            } else {
                lastFailed = integration.getIntegrationTime();
                ++numberOfFailed;
            }
        }
        
        fillCallsStatsIntegrationData(lastSuccessful, lastFailed, numberOfSuccessful, numberOfFailed);
    }

    /**
     * Wypełnia danymi widoki sekcji o integracji statystyk połączeń telefonicznych
     * 
     * @param lastSuccessful ostatnia udana integracja
     * @param lastFailed ostatnia nieudana integracja
     * @param numberOfSuccessful liczba udanych integracji
     * @param numberOfFailed liczba nieudanych integracji
     */
    private void fillCallsStatsIntegrationData(long lastSuccessful, long lastFailed,
            int numberOfSuccessful, int numberOfFailed){
        TextView lastSuccessfulView = (TextView) topLayout
                .findViewById(R.id.calls_last_successful);
        TextView lastFailedView = (TextView) topLayout
                .findViewById(R.id.calls_last_failed);
        TextView numberOfSuccessfulView = (TextView) topLayout
                .findViewById(R.id.calls_number_of_successful);
        TextView numberOfFailedView = (TextView) topLayout
                .findViewById(R.id.calls_number_of_failed);
        
        if(lastSuccessful != -1l){
            lastSuccessfulView.setText(DATE_FORMATTER.format(new Date(lastSuccessful)));
        }
        if(lastFailed != -1l){
            lastFailedView.setText(DATE_FORMATTER.format(new Date(lastFailed)));
        }
        numberOfSuccessfulView.setText(String.valueOf(numberOfSuccessful));
        numberOfFailedView.setText(String.valueOf(numberOfFailed));
    }
    
    
    /**
     * Wypełnia informację o statusie działania serwisu lokalizacji
     */
    private void fillLocationServiceStatus(){
        TextView locationServiceStatus = (TextView) topLayout.findViewById(R.id.location_service_status);
        
        if(LocationAlarmReceiver.isFetchingLocationsRunning(getApplicationContext())){
            locationServiceStatus.setText(R.string.location_status_active);
            locationServiceStatus.setTextColor(Color.GREEN);
            
        } else {
            locationServiceStatus.setText(R.string.location_status_inactive);
            locationServiceStatus.setTextColor(Color.RED);
            
        }
    }
    
    
    /**
     * Wypełnia informację o statusie działania okresowej integracji
     */
    private void fillPeriodicalIntegrationStatus(){
        TextView periodicalIntegrationStatus = (TextView) topLayout.findViewById(R.id.periodical_integration_status);
        
        if(PeriodicalIntegrationReceiver.isPeriodicalIntegrationRunning(getApplicationContext())){
            periodicalIntegrationStatus.setText(R.string.periodical_integration_active);
            periodicalIntegrationStatus.setTextColor(Color.GREEN);
            
        } else {
            periodicalIntegrationStatus.setText(R.string.periodical_integration_inactive);
            periodicalIntegrationStatus.setTextColor(Color.RED);
            
        }
    }
    
    //--------------------------------------------------------------------
    // Sterowanie
    //--------------------------------------------------------------------
    
    private void doInitialSettings(){
        Context context = getApplicationContext();
        SharedPreferences sharedPreferences = getPreferences(MODE_PRIVATE);
        if(! sharedPreferences.getBoolean(FIRST_RUN_SHARED_PREFERENCES_KEY, false)){
            // pierwsze uruchomienie - inicjalizacja
            LoggingUtil.d(this, "First application run - doing initial settings");
            
            if(Constants.FORCE_DROP_DB_AT_FIRST_RUN){
                // wymuszenie usunięcia dotychczasowej bazy danych
                // przydatne w trakcie testowania aplikacji
                LoggingUtil.d(this, "DROPPING get_to_know_me DATABASE");
                context.deleteDatabase(DBOpenHelper.DB_NAME);
            }
            
            // uruchomienie serwisu lokalizacji
            startLocationService();
            
            // uruchomienie okresowej integracji
            startPeriodicalIntegration();
            
            sharedPreferences.edit()
                    .putBoolean(FIRST_RUN_SHARED_PREFERENCES_KEY, true)
                    .commit();
            
        } else {
            // sprawdzamy czy pobieranie lokalizacji jest możliwe
            if(!isLocationNetworkProviderEnabled()){
                showEnableNetworkProviderAlert();
            }
        }
    }
    
    
    private boolean isLocationNetworkProviderEnabled(){
        LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        return locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    }
    
    
    private void showEnableNetworkProviderAlert(){
        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(R.string.location_network_provider_disabled_message)
               .setCancelable(false)
               .setNeutralButton("OK", new DialogInterface.OnClickListener() {
                   public void onClick(final DialogInterface dialog, final int id) {
                       startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
                   }
               });
        final AlertDialog alert = builder.create();
        alert.show();
    }

    
    
    private void startLocationService(){
        if(!isLocationNetworkProviderEnabled()){
            // wyłączone pobieranie lokalizacji
            showEnableNetworkProviderAlert();
            return;
        }
        
        Intent intent = new Intent(LocationAlarmReceiver.START_FETCHING_LOCATIONS_ACTION);
        sendBroadcast(intent);
    }
    
    private void stopLocationService(){
        Intent intent = new Intent(LocationAlarmReceiver.STOP_FETCHING_LOCATIONS_ACTION);
        sendBroadcast(intent);
    }

    
    private void startIntegration(){
        Intent intent = new Intent(PeriodicalIntegrationReceiver.DO_INTEGRATION_ACTION);
        sendBroadcast(intent);
    }
    
    private void startPeriodicalIntegration(){
        Intent intent = new Intent(PeriodicalIntegrationReceiver.START_PERIODICAL_INTEGRATION_ACTION);
        sendBroadcast(intent);
    }
    
    private void stopPeriodicalIntegration(){
        Intent intent = new Intent(PeriodicalIntegrationReceiver.STOP_PERIODICAL_INTEGRATION_ACTION);
        sendBroadcast(intent);
    }
}
